package com.atguigu.gmall.order.service.impl;

import com.alibaba.fastjson.JSON;
import com.atguigu.gmall.common.constant.MqConst;
import com.atguigu.gmall.common.service.RabbitService;
import com.atguigu.gmall.common.util.HttpClientUtil;
import com.atguigu.gmall.model.enums.OrderStatus;
import com.atguigu.gmall.model.enums.ProcessStatus;
import com.atguigu.gmall.model.order.OrderDetail;
import com.atguigu.gmall.model.order.OrderInfo;
import com.atguigu.gmall.order.mapper.OrderDetailMapper;
import com.atguigu.gmall.order.mapper.OrderInfoMapper;
import com.atguigu.gmall.order.service.OrderService;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.collect.Ordering;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;

/**
 * @author atguigu-mqx
 */
@Service
public class OrderServiceImpl extends ServiceImpl<OrderInfoMapper,OrderInfo> implements OrderService {

    //  服务层调用mapper 层！
    @Autowired
    private OrderInfoMapper orderInfoMapper;

    @Autowired
    private OrderDetailMapper orderDetailMapper;

    @Autowired
    private RedisTemplate redisTemplate;

    @Value("${ware.url}")
    private String wareUrl; // wareUrl=http://localhost:9001

    @Autowired
    private RabbitService rabbitService;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long saveOrderInfo(OrderInfo orderInfo) {
        /*
        1.  看各个表对应的字段！
        2.  注意事务！
         */
        //  总金额，状态，userId{控制器！},第三方交易编号，订单主题，创建，过期时间，进度状态
        orderInfo.sumTotalAmount();
        orderInfo.setOrderStatus(OrderStatus.UNPAID.name());
        String outTradeNo = "ATGUIGU" + System.currentTimeMillis() + "" + new Random().nextInt(1000); // 保证支付幂等性！这个第三方交易编号一定不能重复！
        orderInfo.setOutTradeNo(outTradeNo);
        orderInfo.setTradeBody("买彩电....");
        //  拼接商品的skuName！
        //        List<OrderDetail> orderDetailList = orderInfo.getOrderDetailList();
        //        StringBuilder sb = new StringBuilder();
        //        for (OrderDetail orderDetail : orderDetailList) {
        //            sb.append(orderDetail.getSkuName());
        //        }
        //        if (sb.length()>200){
        //            orderInfo.setTradeBody(sb.substring(0,200));
        //        }else {
        //            orderInfo.setTradeBody(sb.toString());
        //        }
        orderInfo.setCreateTime(new Date());
        Calendar calendar = Calendar.getInstance();
        calendar.add(Calendar.DATE,1);
        orderInfo.setExpireTime(calendar.getTime());// 过期时间 +1天
        //  可以从进度状态中获取到订单状态！
        orderInfo.setProcessStatus(ProcessStatus.UNPAID.name());
        orderInfoMapper.insert(orderInfo);

        //  订单明细：
        List<OrderDetail> orderDetailList = orderInfo.getOrderDetailList();
        for (OrderDetail orderDetail : orderDetailList) {
            orderDetail.setOrderId(orderInfo.getId());
            orderDetail.setCreateTime(new Date());
            orderDetailMapper.insert(orderDetail);
        }
        Long orderId = orderInfo.getId();
        //  发送想消息： 内容是根据消费者要做什么功能来决定的?
        this.rabbitService.sendDelayMessage(MqConst.EXCHANGE_DIRECT_ORDER_CANCEL,MqConst.ROUTING_ORDER_CANCEL,orderId,MqConst.DELAY_TIME);
        //  返回orderId
        return orderId;
    }

    @Override
    public String getTradeNo(String userId) {
        //  生产流水号
        String tradeNo = UUID.randomUUID().toString();
        String tradeNoKey = "user:" + userId + ":tradeCode";
        //  存储到缓存！
        this.redisTemplate.opsForValue().set(tradeNoKey,tradeNo);
        //  返回流水号
        return tradeNo;
    }

    @Override
    public Boolean checkTradeNo(String tradeNo, String userId) {
        //  获取缓存的key
        String tradeNoKey = "user:" + userId + ":tradeCode";
        String str = (String) this.redisTemplate.opsForValue().get(tradeNoKey);
        //  返回比较结果
        return tradeNo.equals(str);
    }

    @Override
    public void deleteTradeNo(String userId) {
        //  获取缓存的key
        String tradeNoKey = "user:" + userId + ":tradeCode";
        this.redisTemplate.delete(tradeNoKey);
    }

    @Override
    public boolean checkStock(Long skuId, Integer skuNum) {
        //  远程调用 http://localhost:9001/hasStock?skuId=10221&num=2 ; ware库存系统：spring boot 单独开发的！没有spring could！
        //  wareUrl=http://localhost:9001
        String result = HttpClientUtil.doGet(wareUrl + "/hasStock?skuId=" + skuId + "&num=" + skuNum);
        //  返回值 1：有  0：无
        return "1".equals(result);
    }

    @Override
    public void execExpiredOrder(Long orderId) {
        //  本质：更新状态！
        //        OrderInfo orderInfo = new OrderInfo();
        //        orderInfo.setId(orderId);
        //        orderInfo.setOrderStatus(OrderStatus.CLOSED.name());
        //        orderInfo.setProcessStatus(ProcessStatus.CLOSED.name());
        //        //  更新数据！
        //        orderInfoMapper.updateById(orderInfo);

        updateOrderStatus(orderId, ProcessStatus.CLOSED);

        //  发送消息更新paymentInfo 记录！
        this.rabbitService.sendMessage(MqConst.EXCHANGE_DIRECT_PAYMENT_CLOSE,MqConst.ROUTING_PAYMENT_CLOSE,orderId);
    }

    //  后续会根据订单Id 进行更新状态！ 更新成支付，发货等！ 做方法抽取！
    //  从进度状态中能够获取订单状态！
    public void updateOrderStatus(Long orderId, ProcessStatus processStatus) {
        OrderInfo orderInfo = new OrderInfo();
        orderInfo.setId(orderId);
        orderInfo.setOrderStatus(processStatus.getOrderStatus().name());
        orderInfo.setProcessStatus(processStatus.name());
        //  更新数据！
        orderInfoMapper.updateById(orderInfo);
    }

    @Override
    public OrderInfo getOrderInfo(Long orderId) {
        //  获取orderInfo 对象
        OrderInfo orderInfo = orderInfoMapper.selectById(orderId);
        if (orderInfo!=null){
            //  获取订单明细
            QueryWrapper<OrderDetail> orderDetailQueryWrapper = new QueryWrapper<>();
            orderDetailQueryWrapper.eq("order_id",orderId);
            List<OrderDetail> orderDetailList = orderDetailMapper.selectList(orderDetailQueryWrapper);
            orderInfo.setOrderDetailList(orderDetailList);
        }
        //  返回orderInfo
        return orderInfo;
    }

    @Override
    public void sendOrderStatus(Long orderId) {
        //  更新订单的状态：
        this.updateOrderStatus(orderId,ProcessStatus.NOTIFIED_WARE);
        //  根据orderId 获取到orderInfo对象 {orderDetailList}
        OrderInfo orderInfo = this.getOrderInfo(orderId);
        //  接口中要的是Json 字符串！ 而且是orderInfo 和orderDetail 中的部分字段！
        //  可以将orderInfo，orderDetail 中的字段存储到一个 Map 集合中！
        Map map = this.initWareOrder(orderInfo);

        //  发送消息：
        this.rabbitService.sendMessage(MqConst.EXCHANGE_DIRECT_WARE_STOCK,MqConst.ROUTING_WARE_STOCK, JSON.toJSONString(map));
    }

    //  将orderInfo 转换为map 集合！
    public Map initWareOrder(OrderInfo orderInfo) {
        //  什么一个map 集合
        Map<String, Object> map = new HashMap<>();

        map.put("orderId",orderInfo.getId());
        map.put("consignee", orderInfo.getConsignee());
        map.put("consigneeTel", orderInfo.getConsigneeTel());
        map.put("orderComment", orderInfo.getOrderComment());
        map.put("orderBody", orderInfo.getTradeBody());
        map.put("deliveryAddress", orderInfo.getDeliveryAddress());
        map.put("paymentWay", "2");
        map.put("wareId", orderInfo.getWareId());   //  拆分库存时使用！
        List<Map> list = new ArrayList<>();
        List<OrderDetail> orderDetailList = orderInfo.getOrderDetailList();
        for (OrderDetail orderDetail : orderDetailList) {
            //  声明一个map集合
            HashMap<String, Object> hashMap = new HashMap<>();
            hashMap.put("skuId",orderDetail.getSkuId());
            hashMap.put("skuNum",orderDetail.getSkuNum());
            hashMap.put("skuName",orderDetail.getSkuName());

            //  将map 集合添加到list 中
            list.add(hashMap);
        }
        map.put("details",list);
        //  返回
        return map;
    }

    @Override
    public List<OrderInfo> orderSplit(String orderId, String wareSkuMap) {
        List<OrderInfo> subOrderInfoList = new ArrayList<>();
        //  写拆单业务逻辑！
        /*
        1.  知道原始订单是谁！
        2.  wareSkuMap [{"wareId":"1","skuIds":["2","10"]},{"wareId":"2","skuIds":["3"]}] 必须将其转换为我们能操作的对象！
        3.  创建新的子订单 new OrderInfo(); 并给子订单赋值！
        4.  将子订单保存到数据库中！
        5.  将子订单对象添加到这个集合中！
        6.  修改原始订单状态！
         */
        OrderInfo orderInfoOrigin = this.getOrderInfo(Long.parseLong(orderId));
        //  将对象转换为List<Map>
        List<Map> mapList = JSON.parseArray(wareSkuMap, Map.class);

        //  循环遍历这个集合
        for (Map map : mapList) {
            //  获取到了仓库Id
            String wareId = (String) map.get("wareId");
            //  获取到仓库Id 中对应的订单明细 skuId
            List<String> skuIdList = (List<String>) map.get("skuIds");
            //  创建一个新的子订单
            OrderInfo subOrderInfo = new OrderInfo();

            //  属性拷贝！
            BeanUtils.copyProperties(orderInfoOrigin,subOrderInfo);
            //  注意事项：
            subOrderInfo.setId(null);
            //  赋值父订单Id
            subOrderInfo.setParentOrderId(Long.parseLong(orderId));
            //  赋值一个仓库Id
            subOrderInfo.setWareId(wareId);
            //  重新计算子订单价格：
            //  但是，它需要子订单的明细集合，才能调用这个方法计算！
            //  获取到原始订单明细
            List<OrderDetail> orderDetailList = orderInfoOrigin.getOrderDetailList();
            //  建立一个集合来存储子订单明细
            List<OrderDetail> orderDetails = new ArrayList<>();
            //  获取子订单明细
            for (OrderDetail orderDetail : orderDetailList) {
                //  编写这个skuIdList 集合
                for (String skuId : skuIdList) {
                    //  比较
                    if (orderDetail.getSkuId().longValue() ==  Long.parseLong(skuId)){
                        orderDetails.add(orderDetail);
                    }
                }
            }
            subOrderInfo.setOrderDetailList(orderDetails);
            //  207,208 子订单：
            subOrderInfo.sumTotalAmount();

            //  保存子订单
            this.saveOrderInfo(subOrderInfo);

            //  将这个子订单添加到子订单集合
            subOrderInfoList.add(subOrderInfo);

        }
        //  修改原始订单状态
        this.updateOrderStatus(Long.parseLong(orderId),ProcessStatus.SPLIT);
        //  返回
        return subOrderInfoList;
    }

    @Override
    public void execExpiredOrder(Long orderId, String flag) {
        //  必须关闭orderInfo
        updateOrderStatus(orderId, ProcessStatus.CLOSED);
        //  发送消息关闭paymentInfo
        if("2".equals(flag)){
            //  发送消息更新paymentInfo 记录！
            this.rabbitService.sendMessage(MqConst.EXCHANGE_DIRECT_PAYMENT_CLOSE,MqConst.ROUTING_PAYMENT_CLOSE,orderId);
        }
    }

}
